package Wix::BuildManager;

use Cwd qw/chdir getcwd/;
use File::Path;
use File::Basename;
use FindBin;
use Data::Dumper;
use Digest::MD5 qw/md5_hex/;
use Wix::Harvest;
use Wix::Tag::Wix;
use Wix::Tag::Package;
use Wix::Tag::Product;
use Wix::Tag::Media;
use Wix::Tag::Feature;
use Wix::Tag::UIRef;
use Wix::Tag::Property;

use strict;

sub new($) {
	my ($class, $options) = @_;
	
	my $self = {
		_OPTIONS => $options,
		_TMPDIR_ROOT => sprintf('%s\\WixBuilder', $ENV{TEMP}),
		_WXSUIFILE => sprintf('%s\\WixUI_Custom.wxs', $FindBin::Bin),
	};
	
	$self->{_BUILDDIR} = sprintf('%s\\%s', $self->{_TMPDIR_ROOT}, md5_hex($self->{_OPTIONS}->{NAME}));
	$self->{_WXSFILE} = sprintf('%s\\main.wxs', $self->{_BUILDDIR});
	$self->{_WXSOBJFILE} = sprintf('%s\\main.wixobj', $self->{_BUILDDIR});
	$self->{_WXSUIOBJFILE} = sprintf('%s\\WixUI_Custom.wixobj', $self->{_BUILDDIR});
	
	if (-d $self->{_BUILDDIR}) {
		rmtree($self->{_BUILDDIR});
	}
	
	mkpath($self->{_BUILDDIR});
	
	return bless($self, $class);
}

sub generateWxs() {
	my ($self) = @_;
	
	my $wix = Wix::Tag::Wix->new();
	
	my $package = Wix::Tag::Package->new(
		{
			DESCRIPTION => $self->{_OPTIONS}->{DESCRIPTION}	
		}
	);

	my $product = Wix::Tag::Product->new(
		{
			NAME => $self->{_OPTIONS}->{NAME},
			VERSION => $self->{_OPTIONS}->{VERSION},
			MANUFACTURER => => $self->{_OPTIONS}->{AUTHOR}
		}
	);
	
	$product->addPackage($package);
	$product->addMedia(Wix::Tag::Media->new());
	
	my $pfiles = Wix::Tag::Directory::GetProgramFiles();
	
	$pfiles->addDirectory(Wix::Tag::Directory::GetApplicationRoot($self->{_OPTIONS}->{NAME}));
		
	my $target = Wix::Tag::Directory::GetTarget();
	$target->addDirectory($pfiles);
	
	$product->addDirectory($target);
	
	foreach my $name (keys %{$self->{_OPTIONS}->{FEATURES}}) {
		my $fref = $self->{_OPTIONS}->{FEATURES}->{$name};
		
		if (defined(my $shortcuts = $fref->{SHORTCUTS})) {
			my $appdigest = md5_hex($self->{_OPTIONS}->{NAME});
			
			foreach my $type (qw/START DESKTOP/) {
				if (defined(my $tref = $shortcuts->{$type})) {
					my $root;
					my $dirs = {};
					
					my $rootid;
					
					if ($type eq 'START') {
						$root = Wix::Tag::Directory::GetStartMenu();
						$rootid = sprintf('STARTDIR_%s', $appdigest);
					}
					elsif ($type eq 'DESKTOP') {
						$root = Wix::Tag::Directory::GetDesktop();
						$rootid = sprintf('DESKTOPDIR_%s', $appdigest);
					}
					
					$dirs->{$rootid} = Wix::Tag::Directory->new(
						{
							ID => $rootid, 
							NAME => $self->{_OPTIONS}->{NAME}
						}
					);
					
					$root->addDirectory($dirs->{$rootid});
					
					while (my ($k, $v) = each %{$tref}) {
						my $link = $v->{LINK};
						$link =~ s/\\/\//g;
						$link =~ s/^(.*)\/(.*)$/$1/;
						
						my ($key, $ldref);
						
						foreach (split '/', $link) {
							if ($link eq $_) {
								unless ($v->{NOROOT}) {
									$ldref = $rootid;	
								}
								last;
							}
							
							my $prevkey = $key;
							
							if ($key) {
								$key .= "/$_";
							}
							else {
								$key = $_;
							}
							
							my $keyref = md5_hex($key);
							$ldref = sprintf('DIR_%s', $keyref);
							
							$dirs->{$keyref} = Wix::Tag::Directory->new(
								{
									ID => $ldref,
									NAME => $_
								}
							);
							
							if ($prevkey) {
								$dirs->{md5_hex($prevkey)}->addDirectory($dirs->{$keyref});
							}
							else {
								if ($v->{NOROOT}) {
									$root->addDirectory($dirs->{$keyref});	
								}
								else {
									$dirs->{$rootid}->addDirectory($dirs->{$keyref});
								}
							}
						}
						
						if ($ldref) {
							$v->{DIRECTORYREF} = $ldref 
						}
						else {
							$v->{DIRECTORYREF} = $root->getAttr('Id');
						}
					}
					
					$target->addDirectory($root);			
				}
			}
		}
		
		my $harvest = Wix::Harvest::Harvest($fref);
		
		my $feature = Wix::Tag::Feature->new(
			{
				ID => sprintf('FEATURE_%s', uc $name),
				TITLE => $name,
				LEVEL => 1	
			}
		);
		
		$feature->addComponentGroupRef($harvest->getComponentGroup()->getComponentGroupRef());
		$product->addDirectoryRef($harvest->{_DIRECTORY});
		$product->addComponentGroup($harvest->getComponentGroup());
		$product->addFeature($feature);
	}
	
	$product->addUIRef(Wix::Tag::UIRef::GetCustom());	

	$product->addProperty(Wix::Tag::Property::GetInstallDir());
	
	$wix->addProduct($product);
	
	open WXS_FILE, sprintf('>%s', $self->{_WXSFILE});
	print WXS_FILE $wix->getSource();	
	close WXS_FILE;
}

sub candle() {
	my ($self) = @_;
	
	my @args = ();
	push @args, sprintf('"%s" "%s"', $self->{_WXSFILE}, $self->{_WXSUIFILE});
	
	return Execute('candle', \@args);
}

sub light() {
	my ($self) = @_;
	
	my @args = ();
	push @args, '-spdb';
	push @args, '-ext WixUIExtension';
	push @args, '-sice:ICE64';
	push @args, '-sice:ICE47';
	push @args, sprintf('-o "%s %s.msi"', $self->{_OPTIONS}->{NAME}, $self->{_OPTIONS}->{VERSION});
	push @args, sprintf('"%s" "%s"', $self->{_WXSOBJFILE}, $self->{_WXSUIOBJFILE});
	
	return Execute('light', \@args);
}

sub build() {
	my ($self) = @_;
	
	my $cwd = getcwd();
	
	chdir $self->{_BUILDDIR}, "\n";
	
	$self->generateWxs();
	
	$self->candle();
	
	chdir $cwd;
	
	$self->light();
}

sub Execute($;$) {
	my ($cmd, $args) = @_;
	
	my $cmdstring;
	
	if ($args) {
		$cmdstring = sprintf('%s %s', $cmd, join(' ', @{$args})); 
	} 
	else {
		$cmdstring = $cmd;
	}
	
	open PIPE, sprintf('%s 2>&1 |', $cmdstring);

	while (my $line = <PIPE>) {
		chomp($line);
		
		print STDERR $line, "\n";		
	}

	close PIPE;
}

1;